/**
 * Qing JavaScript Library
 * 多库共存，多版本共存
 * window['qing_framework']请保留
 *
 * refer to mass Framework
 * https://github.com/RubyLouvre/mass-Framework
 * by 司徒正美 
 *
 * @author tom.wang<tom.wang.sz@qq.com>
 */
;(function( window, undefined ) {
	var _$ = window.$, // 保存$
		qing = 1.0, // 版本
		debug = true, // 是否调试，发布后设置为false
		qingNS = 'qing_framework', // 不同的版本这个不要改变
		namespace = window[qingNS];
	
	// 多版本共存
	// todo: 如果第一次加载jQuery或其他类库，第二次加载Qing的某个版本且不占用$，第三次再加载Qing，如何做到多版本共存
	if(typeof(namespace) !== 'function') {
		namespace = window[qingNS] = $;
		namespace.qingVersions = {length : 0}; // 保存当前加载的所有qing框架的版本号
	}
	
	var qingVersions = namespace.qingVersions;
	
	if(!qingVersions[qing]) {
		// 当前版本不在版本库中
		namespace[qing] = $;
		++qingVersions.length;
		qingVersions[qing] = true;
	} else {
		// 已经加载了当前版本，直接返回
		return;
	}
	
	var doc = window.document,
	    w3c = doc.dispatchEvent, //w3c事件模型
		html = doc.documentElement,
		head = doc.head || doc.getElementsByTagName('head')[0],
		class2type = {
			"[object HTMLDocument]"   : "Document",
			"[object HTMLCollection]" : "NodeList",
			"[object StaticNodeList]" : "NodeList",
			"[object IXMLDOMNodeList]": "NodeList",
			"[object DOMWindow]"      : "Window"  ,
			"[object global]"         : "Window"  ,
			"null"                    : "Null"    ,
			"NaN"                     : "NaN"     ,
			"undefined"               : "Undefined"
		},
		toString = class2type.toString,
		hasOwn = class2type.hasOwnProperty,
		slice = [].slice,
		splice = [].splice,
		rword = /[^, ]+/g;
		
	"Boolean,Number,String,Function,Array,Date,RegExp,Window,Document,Arguments,NodeList".replace( rword, function( name ){
		class2type[ "[object " + name + "]" ] = name;
	});
	
	// 扩展JavaScript
	(function(){
		//fix ie for..in bug：ie中，如果对象重写了以下方法，for...in语句无法将这些方法枚举出来
		var DONT_ENUM = "propertyIsEnumerable,isPrototypeOf,hasOwnProperty,toLocaleString,toString,valueOf,constructor".split(","),
		P = "prototype";
		for (var i in {
			toString: 1
		}){
			DONT_ENUM = false;
		}
		//第二个参数仅在浏览器支持Object.defineProperties时可用
		mix(Object,{
			//取得其所有键名以数组形式返回
			keys: function(obj){//ecma262v5 15.2.3.14
				var result = [];
				for(var key in obj ) if(hasOwn.call(obj,key)){
					result.push(key)
				}
				if(DONT_ENUM && obj){
					for(var i = 0 ;key =DONT_ENUM[i++]; ){
						if(hasOwn.call(obj,key)){
							result.push(key);
						}
					}
				}
				return result;
			},
			getPrototypeOf  :  typeof P.__proto__ === "object" ?  function(obj){
				return obj.__proto__;
			}:function(obj){
				return obj.constructor[P];
			}

		},false);

		//用于创建javascript1.6 Array的迭代器
		function iterator(vars, body, ret) {
			var fun = 'for(var '+vars+'i=0,n = this.length;i < n;i++){'+
			body.replace('_', '((i in this) && fn.call(scope,this[i],i,this))')
			+'}'+ret
			return new Function("fn,scope",fun);
		}
		mix(Array[P],{
			//定位类 返回指定项首次出现的索引。
			indexOf: function (item, index) {
				var n = this.length, i = ~~index;
				if (i < 0) i += n;
				for (; i < n; i++)
					if ( this[i] === item) return i;
				return -1;
			},
			//定位类 返回指定项最后一次出现的索引。
			lastIndexOf: function (item, index) {
				var n = this.length,
				i = index == null ? n - 1 : index;
				if (i < 0) i = Math.max(0, n + i);
				for (; i >= 0; i--)
					if (this[i] === item) return i;
				return -1;
			},
			//迭代类 在数组中的每个项上运行一个函数。
			forEach : iterator('', '_', ''),
			//迭代类 在数组中的每个项上运行一个函数，如果此函数的值为真，则此元素作为新数组的元素收集起来，并返回新数组
			filter : iterator('r=[],j=0,', 'if(_)r[j++]=this[i]', 'return r'),
			//迭代类  在数组中的每个项上运行一个函数，并将全部结果作为数组返回。
			map :  iterator('r=[],', 'r[i]=_', 'return r'),
			//迭代类  在数组中的每个项上运行一个函数，若存在任意的结果返回真，则返回真值。
			some : iterator('', 'if(_)return true', 'return false'),
			//迭代类  在数组中的每个项上运行一个函数，若所有结果都返回真值，此方法亦返回真值。
			every : iterator('', 'if(!_)return false', 'return true'),
			//归化类 javascript1.8  对该数组的每项和前一次调用的结果运行一个函数，收集最后的结果。
			reduce: function (fn, lastResult, scope) {
				if (this.length == 0) return lastResult;
				var i = lastResult !== undefined ? 0 : 1;
				var result = lastResult !== undefined ? lastResult : this[0];
				for (var n = this.length; i < n; i++)
					result = fn.call(scope, result, this[i], i, this);
				return result;
			},
			//归化类 javascript1.8 同上，但从右向左执行。
			reduceRight: function (fn, lastResult, scope) {
				var array = this.concat().reverse();
				return array.reduce(fn, lastResult, scope);
			}
		},false);
	   
		//修正IE67下unshift不返回数组长度的问题
		//http://www.cnblogs.com/rubylouvre/archive/2010/01/14/1647751.html
		if([].unshift(1) !== 1){
			var _unshift = Array[P].unshift;
			Array[P].unshift = function(){
				_unshift.apply(this, arguments);
				return this.length; //返回新数组的长度
			}
		}
		if(!Array.isArray){
			Array.isArray = function(obj){
				return toString.call(obj) =="[object Array]";
			};
		}
		//String扩展
		mix(String[P],{
			//ecma262v5 15.5.4.20
			//http://www.cnblogs.com/rubylouvre/archive/2009/09/18/1568794.html
			//'      dfsd '.trim() === 'dfsd''
			trim: function(){
				return  this.replace(/^[\s\xA0]+/,"").replace(/[\s\xA0]+$/,'')
			}
		},false);

		mix(Function[P],{
			//ecma262v5 15.3.4.5
			bind:function(scope) {
				if (arguments.length < 2 && scope===void 0) return this;
				var fn = this, argv = arguments;
				return function() {
					var args = [], i;
					for(i = 1; i < argv.length; i++)
						args.push(argv[i]);
					for(i = 0; i < arguments.length; i++)
						args.push(arguments[i]);
					return fn.apply(scope, args);
				};
			}
		},false);
		// Fix Date.get/setYear() (IE5-7)
		if ((new Date).getYear() > 1900) {
			Date.now = function(){
				return +new Date;
			}
			//http://stackoverflow.com/questions/5763107/javascript-date-getyear-returns-different-result-between-ie-and-firefox-how-to
			Date[P].getYear = function() {
				return this.getFullYear() - 1900;
			};
			Date[P].setYear = function(year) {
				return this.setFullYear(year + 1900);
			};
		}
	})();
	
	/**
	 * Javascript语言增强
	 */
	(function(){
		var global = window, 
		rascii = /[^\x00-\xff]/g,
		rformat = /\\?\#{([^{}]+)\}/gm,
		rnoclose = /^(area|base|basefont|bgsound|br|col|frame|hr|img|input|isindex|link|meta|param|embed|wbr)$/i,
		// JSON RegExp
		rvalidchars = /^[\],:{}\s]*$/,
		rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
		rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
		rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
		str_eval = global.execScript ? "execScript" : "eval",
		//str_body = (global.open + '').replace(/open/g, '');
		str_body = (hasOwn + '').replace(/hasOwnProperty/g, ''); //不使用DOM对象的方法
		mix($,{
			//判定是否是一个朴素的javascript对象（Object或JSON），不是DOM对象，不是BOM对象，不是自定义类的实例。
			isPlainObject : function (obj){
				if(!checkType(obj,"Object") || $.isNative(obj, "reload") ){
					return false;
				}
				try{//不存在hasOwnProperty方法的对象肯定是IE的BOM对象或DOM对象
					for(var key in obj)//只有一个方法是来自其原型立即返回flase
						if(!hasOwn.call(obj, key)){//不能用obj.hasOwnProperty自己查自己
							return false
						}
				}catch(e){
					return false;
				}
				return true;
			},
			//判定method是否为obj的原生方法，如$.isNative(global,"JSON")
			isNative : function(obj, method) {
				var m = obj ? obj[method] : false, r = new RegExp(method, 'g');
				// 编码技巧：内部原生方法转成字符串，将方法名替换成空字符串都是一样的。
				return !!(m && typeof m != 'string' && str_body === (m + '').replace(r, ''));
			},
			/**
			 * 是否为空对象
			 * @param {Object} obj
			 * @return {Boolean}
			 */
			isEmptyObject: function(obj ) {
				for ( var i in obj ){
					return false;
				}
				return true;
			},
			//包括Array,Arguments,NodeList,HTMLCollection,IXMLDOMNodeList与自定义类数组对象
			//select.options集合（它们两个都有item与length属性）
			isArrayLike :  function (obj) {
				if(!obj || obj.document || obj.nodeType || checkType(obj,"Function")) return false;
				return isFinite(obj.length) ;
			},
			//将字符串中的占位符替换为对应的键值
			//http://www.cnblogs.com/rubylouvre/archive/2011/05/02/1972176.html
			format : function(str, object){
				var array = $.slice(arguments,1);
				return str.replace(rformat, function(match, name){
					if (match.charAt(0) == '\\')
						return match.slice(1);
					var index = Number(name)
					if(index >=0 )
						return array[index];
					if(object && object[name] !== void 0)
						return  object[name];
					return  '' ;
				});
			},
			/**
			 * 用于拼接多行HTML片断,免去写<与>与结束标签之苦
			 * todo:如何处理标签嵌套的拼接？
			 * @param {String} tag 可带属性的开始标签
			 * @param {String} innerHTML 可选
			 * @param {Boolean} xml 可选 默认false,使用HTML模式,需要处理空标签
			 * @example var html = T("P title=aaa",T("span","111111")("strong","22222"))("div",T("div",T("span","两层")))("H1",T("span","33333"))('',"这是纯文本");
			 * console.log(html+"");
			 * @return {Function}
			 */
			tag:function (start, content, xml){
				xml = !!xml;
				var chain = function(start, content, xml){
					var html = arguments.callee.html;
					start && html.push("<",start,">");
					content = ''+(content||'');
					content && html.push(content);
					var end = start.split(' ')[0];//取得结束标签
					if(end && (xml || !rnoclose.test(end))){
						html.push("</",end,">");
					}
					return chain;
				}
				chain.html = [];
				chain.toString = function(){
					return this.html.join("");
				}
				return chain(start,content,xml);
			},
			// Generate an integer Array containing an arithmetic progression. A port of
			// the native Python `range()` function. See
			// [the Python documentation](http://docs.python.org/library/functions.html#range).
			range : function(start, stop, step) {
				if (arguments.length <= 1) {
					stop = start || 0;
					start = 0;
				}
				step = arguments[2] || 1;
				var len = Math.max(Math.ceil((stop - start) / step), 0);
				var idx = 0;
				var range = new Array(len);
				while(idx < len) {
					range[idx++] = start;
					start += step;
				}
				return range;
			},
			// && 较 ||优先级更高
			quote : global.JSON && JSON.stringify || String.quote ||  (function(){
				var meta = {
					'\t':'t',
					'\n':'n',
					'\v':'v',
					'f':'f',
					'\r':'\r',
					'\'':'\'',
					'\"':'\"',
					'\\':'\\'
				},
				reg = /[\x00-\x1F\'\"\\\u007F-\uFFFF]/g,
				regFn = function(c){
					if (c in meta) return '\\' + meta[c];
					var ord = c.charCodeAt(0);
					return ord < 0x20   ? '\\x0' + ord.toString(16)
					:  ord < 0x7F   ? '\\'   + c
					:  ord < 0x100  ? '\\x'  + ord.toString(16)
					:  ord < 0x1000 ? '\\u0' + ord.toString(16)
					: '\\u'  + ord.toString(16)
				};
				return function (str) {
					return    '"' + str.replace(reg, regFn)+ '"';
				}
			})(),
			each : function(obj, fn, args ){
				var go = 1, isArray = Array.isArray(args);
				$.lang(obj).forEach( function (el, i){
					if( go && fn.apply(el, isArray ? args : [el, i, obj]) === false){
						go = 0;
					}
				});
			},
			dump : function(obj, indent) {
				indent = indent || "";
				if (obj === null)
					return indent + "null";
				if (obj === void 0)
					return indent + "undefined";
				if (obj.nodeType === 9)
					return indent + "[object Document]";
				if (obj.nodeType)
					return indent + "[object " + (obj.tagName || "Node") +"]";
				var arr = [],type = checkType(obj),self = arguments.callee,next = indent +  "\t";
				switch (type) {
					case "Boolean":
					case "Number":
					case "NaN":
					case "RegExp":
						return indent + obj;
					case "String":
						return indent + $.quote(obj);
					case "Function":
						return (indent + obj).replace(/\n/g, "\n" + indent);
					case "Date":
						return indent + '(new Date(' + obj.valueOf() + '))';
					case "global" :
						return indent + "[object "+type +"]";
					case "NodeList":
					case "Arguments":
					case "Array":
						for (var i = 0, n = obj.length; i < n; ++i)
							arr.push(self(obj[i], next).replace(/^\s* /g, next));
						return indent + "[\n" + arr.join(",\n") + "\n" + indent + "]";
					default:
						if($.isPlainObject(obj)){
							for ( i in obj) {
								arr.push(next + self(i) + ": " + self(obj[i], next).replace(/^\s+/g, ""));
							}
							return indent + "{\n" + arr.join(",\n") + "\n" + indent + "}";
						}else{
							return indent + "[object "+type +"]";
						}
				}
			},
			//http://www.schillmania.com/content/projects/javascript-animation-1/
			//http://www.cnblogs.com/rubylouvre/archive/2010/04/09/1708419.html
			parseJS: function( code ) {
				//IE中，global.eval()和eval()一样只在当前作用域生效。
				//Firefox，Safari，Opera中，直接调用eval()为当前作用域，global.eval()调用为全局作用域。
				if ( code && /\S/.test(code) ) {
					try{
						global[str_eval](code);
					}catch(e){ }
				}
			},
			parseJSON: function( data ) {
				if ( typeof data !== "string" || !data ) {
					return null;
				}
				data = data.trim();
				if ( global.JSON && global.JSON.parse ) {
					//使用原生的JSON.parse转换字符串为对象
					return global.JSON.parse( data );
				}
				if ( rvalidchars.test( data.replace( rvalidescape, "@" )
					.replace( rvalidtokens, "]" )
					.replace( rvalidbraces, "")) ) {
					//使用new Function生成一个JSON对象
					//编程技巧：使用function生成json对象，真绝
					return (new Function( "return " + data ))();
				}
				$.error( "Invalid JSON: " + data );
			},

			// Cross-browser xml parsing
			parseXML: function ( data,xml,tmp ) {
				try {
					if ( global.DOMParser ) { // Standard
						tmp = new DOMParser();
						xml = tmp.parseFromString(data , "text/xml" );
					} else { // IE
						xml = new ActiveXObject("Microsoft.XMLDOM" );//"Microsoft.XMLDOM"
						xml.async = "false";
						xml.loadXML( data );
					}
				} catch( e ) {
					xml = undefined;
				}
				if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
					$.log( "Invalid XML: " + data );
				}
				return xml;
			}

		}, false);

		/*"Array,Function".replace(rword, function(name){
			$["is"+name] = function(obj){
				return obj && toString.call(obj) === "[object "+name+"]";
			}
		});
		if(Array.isArray){
			$.isArray = Array.isArray;
		}*/
		var adjustOne = oneObject("String,Array,Number,Object"),
		arrayLike = oneObject("NodeList,Arguments,Object");
		//语言链对象
		$.lang = function(obj){
			var type = checkType(obj), chain = this;
			if(arrayLike[type] &&  isFinite(obj.length)){
				obj = $.slice(obj);
				type = "Array";
			}
			if(adjustOne[type]){
				// chain不是$.lang的实例，说明不是使用new运行$.lang
				if(!(chain instanceof $.lang)){
					chain = new $.lang;
				}
				chain.target = obj;
				chain.type = type;
				return chain;
			}else{// undefined boolean null
				return obj
			}
		}

		$.lang.prototype = {
			constructor:$.lang,
			valueOf:function(){
				return this.target;
			},
			toString:function(){
				return this.target + "";
			}
		};

		var transform = function(method){
			return function(){
				[].unshift.call(arguments,this)
				return method.apply(null,arguments)
			}
		}
		var proto = $.lang.prototype;
		//构建语言链对象的四个重要工具:$.String, $.Array, $.Number, $.Object
		"String,Array,Number,Object".replace(rword, function(type){
			$[type] = function(ext){
				Object.keys(ext).forEach(function(name){
					$[type][name] = ext[name];
					proto[name] = function(){
						var target = this.target;
						var method = target[name] || transform($[this.type][name]);
						return method.apply(target, arguments);
					}
					proto[name+"X"] = function(){
						var result = this[name].apply(this, arguments);
						return $.lang(result) ;
					}
				});
			}
		});

		$.String({
			//判断一个字符串是否包含另一个字符
			contains: function(target, str, separator){
				return (separator) ? !!~(separator + target + separator).indexOf(separator + str + separator) : !!~target.indexOf(str);
			},
			//判定是否以给定字符串开头
			startsWith: function(target, str, ignorecase) {
				var start_str = target.substr(0, str.length);
				return ignorecase ? start_str.toLowerCase() === str.toLowerCase() :
				start_str === str;
			},
			//判定是否以给定字符串结尾
			endsWith: function(target, str, ignorecase) {
				var end_str = target.substring(target.length - str.length);
				return ignorecase ? end_str.toLowerCase() === str.toLowerCase() :
				end_str === str;
			},
			//得到字节长度
			//中文字符计算为2个长度
			byteLen:function(target){
				return target.replace(rascii,"--").length;
			},
			//是否为空白节点
			empty: function (target) {
				return target.valueOf() === '';
			},
			//判定字符串是否只有空白（或者是空字符串）
			blank: function (target) {
				return /^\s*$/.test(target);
			},
			//length，新字符串长度，truncation，新字符串的结尾的字段,返回新字符串
			truncate :function(target, length, truncation) {
				length = length || 30;
				truncation = truncation === void(0) ? '...' : truncation;
				return target.length > length ?
				target.slice(0, length - truncation.length) + truncation : String(target);
			},
			//转换为驼峰风格，a-bcd-xyz转换成aBcdXyz
			camelize:function(target){
				return target.replace(/-([a-z])/g, function($0, $1){
					return $1.toUpperCase();
				});
			},
			//转换为连字符风格，aBcdXyz转换成a_bcd_xyz
			underscored: function(target) {
				return target.replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/\-/g, '_').toLowerCase();
			},
			//首字母大写（剩余其他字符小写）
			capitalize: function(target){
				return target.charAt(0).toUpperCase() + target.substring(1).toLowerCase();
			},
			//转换为整数
			toInt: function(target, radix) {
				return parseInt(target, radix || 10);
			},
			//转换为小数
			toFloat: function(target) {
				return parseFloat(target);
			},
			//转换为十六进制
			toHex: function(target) {
				for (var i = 0, ret = ""; i < target.length; i++) {
					if (target.charCodeAt(i).toString(16).length < 2) {
						ret += '\\x0' + target.charCodeAt(i).toString(16).toUpperCase() ;
					} else {
						ret += '\\x' + target.charCodeAt(i).toString(16).toUpperCase() ;
					}
				}
				return ret;
			},
			//http://stevenlevithan.com/regex/xregexp/
			//将字符串安全格式化为正则表达式的源码
			escapeRegExp: function( target ){
				return target.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
			},

			//http://www.cnblogs.com/rubylouvre/archive/2010/02/09/1666165.html
			//在左边补上一些字符,默认为0
			padLeft: function( target, digits, filling, radix ){
				var num = target.toString(radix || 10);
				filling = filling || "0";
				while(num.length < digits){
					num= filling + num;
				}
				return num;
			},

			//在右边补上一些字符,默认为0
			padRight: function(target, digits, filling, radix){
				var num = target.toString(radix || 10);
				filling = filling || "0";
				while(num.length < digits){
					num +=  filling;
				}
				return num;
			},
			// http://www.cnblogs.com/rubylouvre/archive/2009/11/08/1598383.html
			times :function(target, n){
				var result = "";
				while (n > 0) {
					if (n & 1)
						result += target;
					target += target;
					n >>= 1;
				}
				return result;
			}
		});

		$.Array({
			//深拷贝当前数组
			clone: function(target){
				var i = target.length, result = [];
				while (i--) result[i] = cloneOf(target[i]);
				return result;
			},
			//取得第一个元素或对它进行操作
			//1 如果不提供fn，则直接返回第一个元素
			//2 如果提供fn，则返回fn第一个返回true的元素
			//3 fn的签名Boolean fn(target[i], i, target)，fn中的this指向scope，默认是Window
			first: function(target, fn, scope){
				if(checkType(fn,"Function")){
					for(var i=0, n = target.length; i < n; i++){
						if(fn.call(scope,target[i],i,target)){
							return target[i];
						}
					}
					return null;
				}else{
					return target[0];
				}
			},
			//取得最后一个元素或对它进行操作
			//同first函数，只不过是反向操作
			last: function(target, fn, scope) {
				if(checkType(fn,"Function")){
					for (var i=target.length-1; i > -1; i--) {
						if (fn.call(scope, target[i], i, target)) {
							return target[i];
						}
					}
					return null;
				}else{
					return target[target.length-1];
				}
			},
			//判断数组是否包含此元素
			contains: function (target, item) {
				return !!~target.indexOf(item) ;
			},
			//http://msdn.microsoft.com/zh-cn/library/bb383786.aspx
			//移除 Array 对象中某个元素的第一个匹配项。
			//返回数组，该数组包含一个元素，即被移除的元素
			remove: function (target, item) {
				var index = target.indexOf(item);
				if (~index ) return $.Array.removeAt(target, index);
				return null;
			},
			//移除 Array 对象中指定位置的元素。
			removeAt: function (target, index) {
				return target.splice(index, 1);
			},
			//对数组进行洗牌,但不影响原对象
			// Jonas Raoni Soares Silva http://jsfromhell.com/array/shuffle [v1.0]
			shuffle: function (target) {
				var shuff = target.concat(), j, x, i = shuff.length;
				for (; i > 0; j = parseInt(Math.random() * i), x = shuff[--i], shuff[i] = shuff[j], shuff[j] = x) {};
				return shuff;
			},
			//从数组中随机抽选一个元素出来
			random: function (target) {
				return $.Array.shuffle(target)[0];
			},
			//取得数字数组中值最小的元素
			min: function(target) {
				return Math.min.apply(0, target);
			},
			//取得数字数组中值最大的元素
			max: function(target) {
				return Math.max.apply(0, target);
			},
			//取得对象数组的每个元素的特定属性
			pluck:function(target, name){
				var result = [], prop;
				target.forEach(function(item){
					prop = item[name];
					if(prop != null)
						result.push(prop);
				});
				return result;
			},
			//根据对象的某个属性进行排序
			sortBy: function(target, fn, scope) {
				var array =  target.map(function(item, index) {
					return {
						el: item,
						re: fn.call(scope, item, index)
					};
				}).sort(function(left, right) {
					var a = left.re, b = right.re;
					return a < b ? -1 : a > b ? 1 : 0;
				});
				return $.Array.pluck(array,'el');
			},
			// 以数组形式返回原数组中不为null与undefined的元素
			compact: function (target) {
				return target.filter(function (el) {
					return el != null;
				});
			},
			//取差集(补集)
			diff : function(target, array) {
				var result = target.slice();
				for ( var i = 0; i < result.length; i++ ) {
					for ( var j = 0; j < array.length; j++ ) {
						if ( result[i] === array[j] ) {
							result.splice(i, 1);
							i--;
							break;
						}
					}
				}
				return result;
			},
			merge: function(target, array){
				var i = target.length, j = 0;
				for ( var n = array.length; j < n; j++ ) {
					target[ i++ ] = array[ j ];
				}
				target.length = i;
				return target;
			},
			//取并集
			union :function(target, array){
				$.Array.merge(target, array);
				return $.Array.unique(target);
			},
			//取交集
			intersect:function(target, array){
				return target.filter(function(n) {
					return ~array.indexOf(n);
				});
			},
			// 返回没有重复值的新数组
			unique: function (target) {
				var result = [];
					o:for(var i = 0, n = target.length; i < n; i++) {
						for(var x = i + 1 ; x < n; x++) {
							if(target[x] === target[i])
								continue o;
						}
						result.push(target[i]);
					}
				return result;
			},
			//对数组进行平坦化处理，返回一个一维数组
			flatten: function(target) {
				var result = [],self = $.Array.flatten;
				target.forEach(function(item) {
					if ($.isArray(item)) {
						result = result.concat(self(item));
					} else {
						result.push(item);
					}
				});
				return result;
			}
		});

		var NumberExt = {
			times: function(target, fn, bind) {
				for (var i=0; i < target; i++)
					fn.call(bind, i);
				return target;
			},
			//确保数值在[n1,n2]闭区间之内,如果超出限界,则置换为离它最近的最大值或最小值
			constrain: function(target, n1, n2){
				var a = [n1, n2].sort();
				if(target < a[0]) target = a[0];
				if(target > a[1]) target = a[1];
				return target;
			},
			//求出距离原数最近的那个数
			nearer: function(target, n1, n2){
				var diff1 = Math.abs(target - n1),
				diff2 = Math.abs(target - n2);
				return diff1 < diff2 ? n1 : n2
			},
			upto: function(target, number, fn, scope) {
				for (var i=target+0; i <= number; i++)
					fn.call(scope, i);
				return target;
			},
			downto: function(target, number, fn, scope) {
				for (var i=target+0; i >= number; i--)
					fn.call(scope, i);
				return target;
			},
			// 对target进行四舍五入，保留base位小数
			round: function(target, base) {
				if (base) {
					base = Math.pow(10, base);
					return Math.round(target * base) / base;
				} else {
					return Math.round(target);
				}
			}
		}
		"padLeft,padRight".replace(rword, function(name){
			NumberExt[name] = $.String[name];
		});
		"abs,acos,asin,atan,atan2,ceil,cos,exp,floor,log,pow,sin,sqrt,tan".replace(rword,function(name){
			NumberExt[name] = Math[name];
		});
		$.Number(NumberExt);
		function cloneOf(item){
			var name = checkType(item);
			switch(name){
				case "Array":
				case "Object":
					return $[name].clone(item);
				default:
					return item;
			}
		}
		//使用深拷贝方法将多个对象或数组合并成一个
		function mergeOne(source, key, current){
			if(source[key] && typeof source[key] == "object"){
				$.Object.merge(source[key], current);
			}else {
				source[key] = cloneOf(current)
			}
			return source;
		};

		$.Object({
			//根据传入数组取当前对象相关的键值对组成一个新对象返回
			subset: function(target, props){
				var result = {};
				props.forEach(function(prop){
					result[prop] = target[prop];
				});
				return result;
			},
			//遍历对象的键值对
			forEach: function(target, fn, scope){
				Object.keys(target).forEach(function(name){
					fn.call(scope, target[name], name, target);
				}, target);
			},
			map: function(target, fn, scope){
				return Object.keys(target).map(function(name){
					fn.call(scope, target[name], name, target);
				}, target);
			},
			//进行深拷贝，返回一个新对象，如果是拷贝请使用$.mix
			clone: function(target){
				var clone = {};
				for (var key in target) {
					clone[key] = cloneOf(target[key]);
				}
				return clone;
			},
			merge: function(target, k, v){
				var obj, key;
				//为目标对象添加一个键值对
				if (typeof k === "string")
					return mergeOne(target, k, v);
				//合并多个对象
				for (var i = 1, n = arguments.length; i < n; i++){
					obj = arguments[i];
					for ( key in obj){
						if(obj[key] !== void 0)
							mergeOne(target, key, obj[key]);
					}
				}
				return target;
			},
			//去掉与传入参数相同的元素
			without: function(target, array) {
				var result = {}, key;
				for (key in target) {//相当于构建一个新对象，把不位于传入数组中的元素赋给它
					if (!~array.indexOf(key) ) {
						result[key] = target[key];
					}
				}
				return result;
			}
		});
	})();
	
	// 数据缓存
	// 该模块和事件息息相关
	(function(){
		var remitter = /object|function/;
		mix( $, {
			memcache:{},
			/**
			 * 读写数据
			 * @param target
			 * @param boolean pvt : 是否是私有（private）数据
			 * 如果name指定为'@uuid'，则返回target的uniqueNumber属性值
			 */
			data : function( target, name, data, pvt ) {
				if(target && remitter.test(typeof target)){//只处理HTML节点与普通对象
					var id = target.uniqueNumber || (target.uniqueNumber = $.uuid++);
					if(name === "@uuid"){
						return id;
					}
					// nodeType为1表示是元素节点
					var memcache = target.nodeType === 1 ? $.memcache: target;
					var table = memcache[ "@data_"+id ] || (memcache[ "@data_"+id ] = {});
					if ( !pvt ) {
						table = table.data || (table.data = {});
					}
					var getByName = typeof name === "string";
					if ( name && typeof name == "object" ) {
						mix(table, name);
					}else if(getByName && data !== void 0){
						table[ name ] = data;
					}
					return getByName ? table[ name ] : table;
				}
			},
			_data:function(target,name,data){
				return $.data(target, name, data, true);
			},
			//移除数据
			removeData : function(target, name, pvt){
				if(target && remitter.test(typeof target)){
					var id = target.uniqueNumber;
					if (  !id ) {
						return;
					}
					var memcache = target.nodeType === 1  ? $.memcache : target;
					var table = memcache["@data_"+id], clear = 1, ret = typeof name == "string" ;
					if ( table && ret ) {
						if(!pvt){
							table = table.data;
						}
						if(table){
							ret = table[ name ];
							delete table[ name ];
						}
						var cache = memcache["@data_"+id];
							loop:
							for(var key in cache){
								if(key == "data"){
									for(var i in cache.data){
										clear = 0;
										break loop;
									}
								}else{
									clear = 0;
									break loop;
								}
							}
					}
					if(clear){
						delete memcache["@data_"+id];
					}
					return ret;
				}
			},
			//合并数据
			mergeData:function(neo, src){
				var srcData = $._data(src), neoData = $._data(neo), events = srcData.events;
				if(srcData && neoData){
					$.Object.merge(neoData, srcData);
					if(events){
						delete neoData.handle;
						neoData.events = {};
						for ( var type in events ) {
							for (var i = 0, obj ; obj =  events[ type ][i++]; ) {
								$.event.bind.call( neo, type + ( obj.namespace ? "." : "" ) + obj.namespace, obj.handler, obj.selector, obj.times );
							}
						}
					}
				}
			}
		});
	})();
	
	/**
	 * 类工厂模块
	 * Function $.factory(info) : 根据info构造一个新类，并返回新类的构造函数
	 
	 * Function info['init'] ：新类的构造函数，只是构造函数中运行的一个函数，this指向新类实例，新类的真实构造函数应该是$.factory的返回值
	 * Object info['extend'] : 用于扩展新类的构造函数
	 * Object info['implement'] : 扩展新类的实例属性
	 * Function info['inherit'] : 父类的构造函数
	 */
	(function(){
		var
		P = "prototype",  C = "constructor", I = "@init",S = "_super",
		unextend = oneObject([S,P,I, 'extend', 'implement', 'inherit']), //扩展静态成员的时候，这些键不做扩展
		exclusive = new RegExp([S,C,'setOptions'].join("|")),ron = /on([A-Z][A-Za-z]+)/,
		classOne = oneObject('Object,Array,Function');
		function expand(klass,props){
			'extend,implement'.replace(rword, function(name){
				var modules = props[name];
				if(classOne[checkType(modules)]){
					klass[name].apply(klass,[].concat(modules));
					delete props[name];
				}
			});
			return klass;
		}
		// 这个方法似乎是用来快速绑定事件的，但是不是很清晰
		function setOptions(){
			/*[].unshift(arguments,this.options || {});
			var options = this.options = $.Object.merge.apply(null,arguments),key,match;
			if (typeof this.bind == "function") {
				for (key in options) {
					if ((match = key.match(ron))) {
						this.bind(match[1].toLowerCase(), options[key]);
						delete(options[key]);
					}
				}
			}*/
			return this;
		}
		function _super(){
			var caller = arguments.callee.caller;  // 取得当前方法
			var name = caller._name;  // 取得当前方法名
			var superclass = caller._class[S];//取得当前实例的父类（的构造函数）
			if(superclass && superclass[P][name] ){
				return superclass[P][name].apply(this, arguments.length ? arguments : caller.arguments);
			}else{
				throw name + " no super method!";
			}
		}
		var members =  {
			inherit : function(parent,init) {
				var bridge = function() { };
				if(typeof parent == "function"){
					// 这里把父类的静态属性继承过来了，似乎没有必要
					// 这里的this指的是新类的构造函数，而不是新类的实例
					for(var i in parent){//继承类成员
						this[i] = parent[i];
					}
					bridge[P] = parent[P];
					// 为什么不直接使用this[P] = new parent;呢？
					this[P] = new bridge ;//继承原型成员
					// 子类._super指向父类的构造函数
					this[S]  = parent;//指定父类
				}
				this[I] = (this[I] || []).concat();
				if(init){
					this[I].push(init);
				}
				this.toString = function(){
					return (init || bridge) + "";
				}
				var KP = this[P];
				KP.setOptions = setOptions;
				// 子类方法中通过调用this._super()调用父类中的同名方法
				KP[S] = _super;//绑定方法链
				return  KP[C] = this;
			},
			//扩展类成员（实例成员）
			//参数可以是对象、数组、函数，如果是函数，则会先构造一个它的对象，然后再继承
			implement:function(){
				var target = this[P], reg = exclusive;
				for(var i = 0, module; module = arguments[i++]; ){
					module = typeof module === "function" ? new module :module;
					Object.keys(module).forEach(function(name){
						if(!reg.test(name)){
							var prop = target[name] = module[name];
							if(typeof prop == "function"){
								prop._name  = name;
								prop._class = this;
							}
						}
					},this);
				}
				return this;
			},
			//扩展类成员（静态成员）
			extend: function(){
				var bridge = {};
				for(var i = 0, module; module = arguments[i++]; ){
					mix(bridge, module);
				}
				for(var key in bridge){
					if(!unextend[key]){
						this[key] =  bridge[key];
					}
				}
				return this;
			}
		};
		
		// $.factory可供外部调用
		$.factory = function(obj){
			obj = obj || {};
			var parent  = obj.inherit; //父类构造函数
			var init = obj.init ; //自身构造函数（实际上只是构造函数中调用的一个函数）
			delete obj.inherit;
			delete obj.init;
			var klass = function () {
				// 只可能有一个init，所以这里不需要循环
				for(var i = 0 , init ; init =  klass[I][i++];){
					init.apply(this, arguments);
				}
			};
			mix(klass,members).inherit(parent, init);//添加更多类方法
			//return expand(klass,obj).implement(obj);
			return expand(klass,obj);
		}
	});
	
	mix($, {
		qing : qing, // 版本号
		debug : debug,
		doc : doc,
		html : html,
		head : head,
		rword : rword,
		mix : mix,
		uuid: 1,
		/**
		 * 实现多库共存
		 * @param {String} newName 新的名字空间
		 */
		noConflict : function(newName) {
			window['$'] = _$;
			if(newName) {
				$.exports(newName);
			}
		},
		/**
		 * 将指定的版本导入到全局空间
		 * @param {String} name 命名空间
		 * @param {Float} v 版本号，默认是当前版本号
		 * @return
		 */
		exports : function(name, v) {
			return window[name] = namespace[v || qing];
		},
		isArray : Array.isArray,
		isFunction : function(obj) {
			return checkType(obj, 'Function');
		},
		/**
		 * 获取当前加载的所有Qing版本
		 * @return {Object}
		 */
		getVersions : function() {
			// 获取已经加载的所有qing框架的版本
			return qingVersions;
		},
		/**
		 * 判断当前页面是否加载了指定版本的Qing
		 * @param {Float} 版本号
		 * @return {Boolean} 是否加载了指定版本的Qing
		 */
		hasVersion : function(v) {
			// 判断是否加载了指定版本的qing框架
			return !!qingVersions[v];
		},
		/**
		 * 获取某个指定版本的命名空间
		 * @param {Float} 版本号
		 * @return {Function} Qing框架命名空间
		 */
		getVersion : function(v) {
			return namespace[v];
		},
		/**
         * 用于取得数据的类型（一个参数的情况下）或判定数据的类型（两个参数的情况下）
         * @param {Any} obj 要检测的东西
         * @param {String} str 可选，要比较的类型
         * @return {String|Boolean}
         */
        type: checkType,
        /**
         * 生成键值统一的对象，用于高速化判定
         * @param {Array|String} array 如果是字符串，请用","或空格分开
         * @param {Number} val 可选，默认为1
         * @return {Object}
         */
        oneObject : oneObject,
        /**
         * 数组化
         * @param {ArrayLike} nodes 要处理的类数组对象
         * @param {Number} start 可选。要抽取的片断的起始下标。如果是负数，从后面取起
         * @param {Number} end  可选。规定从何处结束选取
         * @return {Array}
         */
        slice: function ( nodes, start, end ) {
            for(var i = 0, n = nodes.length, result = []; i < n; i++){
                result[i] = nodes[i];
            }
            if ( arguments.length > 1 ) {
                return result.slice( start , ( end || result.length ) );
            } else {
                return result;
            }
        },
        /**
         * 用于调试
         * @param {String} text 要打印的内容
         * @param {Boolean} force 强逼打印到页面上
         */
        log: function ( text, force ){
            if( force ){
                $.require( "ready", function(){
                    var div =  doc.createElement("div");
                    div.innerHTML = text +"";//确保为字符串
                    doc.body.appendChild(div)
                });
            }else if( window.console ){
                window.console.log( text );
            }
        },
		bind: w3c ? function( el, type, fn, phase ){
            el.addEventListener( type, fn, !!phase );
			// 如果绑定匿名函数，可以将该返回值用于unbind
            return fn;
        } : function( el, type, fn ){
            el.attachEvent( "on"+type, fn );
            return fn;
        },
        unbind: w3c ? function( el, type, fn, phase ){
            el.removeEventListener( type, fn || noop, !!phase );
        } : function( el, type, fn ){
            el.detachEvent( "on"+type, fn || noop );
        }
	});
	
	$.noop = $.error = noop;
	
		
	//domReady机制
	var readylist = deferred();
	
	mix($, {
		support : checkSupport() // 特征嗅探
	});
	
	//开始判定页面的加载情况
    if ( doc.readyState === "complete" ) {
        fireReady();
    }else {
        $.bind( doc, ( w3c ? "DOMContentLoaded" : "readystatechange" ), function(){
            if ( w3c || doc.readyState === "complete" ){
                fireReady();
            }
        });
        if( html.doScroll && self.eval === top.eval ){
            doScrollCheck();
        }
    }
    //https://developer.mozilla.org/en/DOM/window.onpopstate
    /*$.bind( window, "popstate", function(){
        $.exports('$');
    });*/
	
	// 导出到全局空间
	$.exports('$');
	
	/**
	 *
	 */
	function $(expr, context) {
		if(checkType( expr,"Function" )) {
			// domReady
			readylist(expr);
		} else {
		}
	}
	
	function noop() {}
	
	/**
     * 糅杂，为一个对象添加更多成员
     * @param {Object} target 目标对象
     * @param {Object} source 属性包
	 * @param {Boolean} override 是否覆盖同名属性，默认为true
     * @return  {Object} 目标对象
     */
	function mix( target, source, override/*=true*/ ){
		// 第一个参数是目标对象，第二个参数及之后的参数是源对象，对后一个参数如果是布尔值，则指定源对象的属性是否覆盖目标对象的属性
		// 如果覆盖是true，则后面的源对象覆盖前面源对象的同名属性
        var args = slice.call( arguments ), key,
        ride = typeof args[args.length - 1] == "boolean" ? args.pop() : true;
        target = target || {};
        for(var i = 1; source = args[i++];){
            for ( key in source ) {
                if (ride || !(key in target)) {
                    target[ key ] = source[ key ];
                }
            }
        }
        return target;
    }
	
	/**
	 * var list = deferred();
	 * list(fn1)(fn2)(fn3); //只有函数才会加入到队列中
	 * list.method = 'pop'; //可以定义处理方法，这里必须是Array拥有的方法，默认是shift
	 * list.complete = function() {}; //可以定义完成时回调，这个方法在fire调用后调用，默认是空函数
	 * list.fire(); //触发队列，所有加入队列的方法都执行后会调用complete方法。
	 */
    function deferred(){//一个简单的异步列队
        var list = [],self = function(fn){
            fn && fn.call && list.push( fn );
			// 编码技巧：函数返回自身
            return self;
        }
        self.method = "shift";
        self.fire = function( fn ){
            while( fn = list[ self.method ]() ){
                fn();
            }
            return list.length ? self : self.complete();
        }
        self.complete = noop;
        return self;
    }
	
	function fireReady(){
		// complete函数不接收参数，参见deferred方法
        readylist.complete = function( fn ){
            checkType( fn, "Function") &&  fn();
        }
        readylist.fire();
        fireReady = noop;
    };
	
	function doScrollCheck() {
        try {
            html.doScroll( "left" );
            fireReady();
        } catch(e) {
            setTimeout( doScrollCheck, 1 );
        }
    };
	
	// 生成对象，用于快速判定
	function oneObject( array, val ){
		if( typeof array == "string" ){
			array = array.match( rword ) || [];
		}
		var result = {}, value = val !== undefined ? val :1;
		for(var i = 0, n = array.length; i < n; i++){
			result[ array[i] ] = value;
		}
		return result;
	};
	
	// 获取或判断对象类型
	function checkType( obj, str ){
		// obj !== obj的情况是NaN
		var result = class2type[ (obj == null || obj !== obj ) ? obj :  toString.call( obj ) ] || obj.nodeName || "#";
		if( result.charAt(0) === "#" ){//兼容旧式浏览器与处理个别情况,如window.opera
			//利用IE678 window == document为true,document == window竟然为false的神奇特性
			if( obj == obj.document && obj.document != obj ){
				result = 'Window'; //返回构造器名字
			}else if( obj.nodeType === 9 ) {
				result = 'Document';//返回构造器名字
			}else if( obj.callee ){
				result = 'Arguments';//返回构造器名字
			}else if( isFinite( obj.length ) && obj.item ){
				result = 'NodeList'; //处理节点集合
			}else{
				result = toString.call( obj ).slice( 8, -1 );
			}
		}
		if( str ){
			return str === result;
		}
		return result;
	};
	
	// 特征嗅探
	function checkSupport() {
		var div = doc.createElement('div');
		div.setAttribute("className", "t");
		div.innerHTML = ' <link/><a href="/nasami"  style="float:left;opacity:.25;">d</a>'+
		'<object><param/></object><table></table><input type="checkbox"/>';
		var a = div.getElementsByTagName("a")[0], style = a.style,
		select = doc.createElement("select"),
		input = div.getElementsByTagName( "input" )[ 0 ],
		opt = select.appendChild( doc.createElement("option") );

		//true为正常，false为不正常
		var support = {
			//标准浏览器只有在table与tr之间不存在tbody的情况下添加tbody，而IE678则笨多了,即在里面为空也乱加tbody
			insertTbody: !div.getElementsByTagName("tbody").length,
			// 在大多数游览器中checkbox的value默认为on，唯有chrome返回空字符串
			checkOn :  input.value === "on",
			//当为select添加一个新option元素时，此option会被选中，但IE与早期的safari却没有这样做,需要访问一下其父元素后才能让它处于选中状态（bug）
			optSelected: !!opt.selected,
			//IE67无法区分href属性与特性（bug）
			attrHref: a.getAttribute("href") === "/nasami",
			//IE67是没有style特性（特性的值的类型为文本），只有el.style（CSSStyleDeclaration）(bug)
			attrStyle: a.getAttribute("style") !== style,
			//对于一些特殊的特性，如class, for, char，IE67需要通过映射方式才能使用getAttribute才能取到值(bug)
			attrProp:div.className !== "t",
			//http://www.cnblogs.com/rubylouvre/archive/2010/05/16/1736535.html
			//是否能正确返回opacity的样式值，IE8返回".25" ，IE9pp2返回0.25，chrome等返回"0.25"
			cssOpacity: style.opacity == "0.25",
			//某些浏览器不支持w3c的cssFloat属性来获取浮动样式，而是使用独家的styleFloat属性
			cssFloat: !!style.cssFloat,
			//IE678的getElementByTagName("*")无法遍历出Object元素下的param元素（bug）
			traverseAll: !!div.getElementsByTagName("param").length,
			//https://prototype.lighthouseapp.com/projects/8886/tickets/264-ie-can-t-create-link-elements-from-html-literals
			//IE678不能通过innerHTML生成link,style,script节点（bug）
			createAll: !!div.getElementsByTagName("link").length,
			//IE6789由于无法识别HTML5的新标签，因此复制这些新元素时也不正确（bug）
			cloneHTML5: doc.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
			//在标准浏览器下，cloneNode(true)是不复制事件的，以防止循环引用无法释放内存，而IE却没有考虑到这一点，把事件复制了（inconformity）
			cloneNode: true,
			//IE6789的innerHTML对于table,thead,tfoot,tbody,tr,col,colgroup,html,title,style,frameset是只读的（inconformity）
			innerHTML: false,
			//IE的insertAdjacentHTML与innerHTML一样，对于许多元素是只读的，另外FF8之前是不支持此API的
			insertAdjacentHTML: false,
			//是否支持createContextualFragment API，此方法发端于FF3，因此许多浏览器不支持或实现存在BUG，但它是将字符串转换为文档碎片的最高效手段
			fastFragment: false,
			//IE67不支持display:inline-block，需要通过hasLayout方法去模拟（bug）
			inlineBlock: true,
			//http://w3help.org/zh-cn/causes/RD1002
			//在IE678中，非替换元素在设置了大小与hasLayout的情况下，会将其父级元素撑大（inconformity）
			keepSize: true,
			//getComputedStyle API是否能支持将margin的百分比原始值自动转换为像素值
			cssPercentedMargin: true
		};
		//IE6789的checkbox、radio控件在cloneNode(true)后，新元素没有继承原来的checked属性（bug）
		input.checked = true;
		support.cloneChecked = (input.cloneNode( true ).checked === true);
		support.appendChecked = input.checked;
		//添加对optDisabled,cloneAll,insertAdjacentHTML,innerHTML,fastFragment的特征嗅探
		//判定disabled的select元素内部的option元素是否也有diabled属性，没有才是标准
		//这个特性用来获取select元素的value值，特别是当select渲染为多选框时，需要注意从中去除disabled的option元素，
		//但在Safari中，获取被设置为disabled的select的值时，由于所有option元素都被设置为disabled，会导致无法获取值。
		select.disabled = true;
		support.optDisabled = !opt.disabled;
		if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
			div.attachEvent("onclick", function click() {
				support.cloneNode = false;//w3c的节点复制是不复制事件的
				div.detachEvent("onclick", click);
			});
			div.cloneNode(true).fireEvent("onclick");
		}
		//判定insertAdjacentHTML是否完美，用于append,prepend,before,after等方法
		var table = div.getElementsByTagName("table")[0]
		try{
			table.insertAdjacentHTML("afterBegin","<tr><td>1</td></tr>");
			support.insertAdjacentHTML = true;
		}catch(e){ }
		try{
			var range =  doc.createRange();
			support.fastFragment = !!range.createContextualFragment("<a>")
		}catch(e){ };
		//判定innerHTML是否完美，用于html方法
		try{
			table.innerHTML = "<tr><td>1</td></tr>";
			support.innerHTML = true;
		}catch(e){};
		a = select = table = opt = style = null;
		readylist(function() {
			//boxModel，inlineBlock，keepSize，cssPercentedMargin这些特征必须等到domReady后才能检测
			var body = doc.body,
			testElement = div.cloneNode(false);
			testElement.style.cssText = "visibility:hidden;width:0;height:0;border:0;margin:0;background:none;padding:0;"
			testElement.appendChild( div );
			body.insertBefore( testElement, body.firstChild );
			//是否遵循w3c的盒子boxModel去计算元素的大小(IE存在怪异模式,inconformity)
			div.innerHTML = "";
			div.style.width = div.style.paddingLeft = "1px";
			support.boxModel = div.offsetWidth === 2;
			if ( typeof div.style.zoom !== "undefined"  ) {
				//IE7以下版本并不支持display: inline-block;样式，而是使用display: inline;
				//并通过其他样式触发其hasLayout形成一种伪inline-block的状态
				div.style.display = "inline";
				div.style.zoom = 1;
				support.inlineBlock = !(div.offsetWidth === 2);
				div.style.display = "";
				div.innerHTML = "<div style='width:4px;'></div>";
				support.keepSize = div.offsetWidth == 2;
				if( window.getComputedStyle ) {
					div.style.marginTop = "1%";
					support.cssPercentedMargin = ( window.getComputedStyle( div, null ) || {
						marginTop: 0
					} ).marginTop !== "1%";
				}

			}
			body.removeChild( testElement );
			div = testElement = null;
		});
		return support;
	}
	
	
	// 选择器模块
	(function(){
		var global = this, DOC = global.document;
		mix($,{
			//http://www.cnblogs.com/rubylouvre/archive/2010/03/14/1685360.
			isXML : function(el){
				var doc = el.ownerDocument || el;
				return doc.createElement("p").nodeName !== doc.createElement("P").nodeName;
			},
			// 第一个节点是否包含第二个节点（如果a和b是同一个节点，则返回false）
			contains:function(a, b){
				if(a.compareDocumentPosition){
					return !!(a.compareDocumentPosition(b) & 16);
				}else if(a.contains){
					//return a !== b && (a.contains ? a.contains(b) : true);
					return a !== b && a.contains(b);
				}
				while ((b = b.parentNode))
					if (a === b) return true;
				return false;
			},
			//获取某个节点的文本，如果此节点为元素节点，则取其childNodes的所有文本，
			//为了让结果在所有浏览器下一致，忽略所有空白节点，因此它非元素的innerText或textContent
			getText : function() {
				return function getText( nodes ) {
					for ( var i = 0, ret = "",node; node = nodes[i++];  ) {
						// 对得文本节点与CDATA的内容
						if ( node.nodeType === 3 || node.nodeType === 4 ) {
							ret += node.nodeValue;
						//取得元素节点的内容
						} else if ( node.nodeType !== 8 ) {
							ret += getText( node.childNodes );
						}
					}
					return ret;
				}
			}(),
			// 问题：取唯一为什么要排序呢
			unique :function(nodes){
				if(nodes.length < 2){
					return nodes;
				}
				var result = [], array = [], uniqResult = {}, node = nodes[0],index, ri = 0;
				//如果支持sourceIndex我们将使用更为高效的节点排序
				//http://www.cnblogs.com/jkisjk/archive/2011/01/28/array_quickly_sortby.html
				if(node.sourceIndex){//IE opera
					for(var i = 0 , n = nodes.length; i< n; i++){
						node = nodes[i];
						index = node.sourceIndex+1e8;
						if(!uniqResult[index]){
							(array[ri++] = new String(index))._ = node;
							uniqResult[index] = 1;
						}
					}
					array.sort();
					while( ri )
						result[--ri] = array[ri]._;
					return result;
				}else {
					var sortOrder = node.compareDocumentPosition ? sortOrder1 : sortOrder2;
					nodes.sort( sortOrder );
					if (sortOrder.hasDuplicate ) {
						for ( i = 1; i < nodes.length; i++ ) {
							if ( nodes[i] === nodes[ i - 1 ] ) {
								nodes.splice( i--, 1 );
							}
						}
					}
					sortOrder.hasDuplicate = false;
					return nodes;
				}
			}
		});
		var reg_combinator  = /^\s*([>+~,\s])\s*(\*|(?:[-\w*]|[^\x00-\xa0]|\\.)*)/;
		var trimLeft = /^\s+/;
		var trimRight = /\s+$/;
		var reg_quick = /^(^|[#.])((?:[-\w]|[^\x00-\xa0]|\\.)+)$/;
		var reg_comma       = /^\s*,\s*/;
		var reg_sequence = /^([#\.:]|\[\s*)((?:[-\w]|[^\x00-\xa0]|\\.)+)/;
		var reg_pseudo        = /^\(\s*("([^"]*)"|'([^']*)'|[^\(\)]*(\([^\(\)]*\))?)\s*\)/;
		var reg_attrib      = /^\s*(?:(\S?=)\s*(?:(['"])(.*?)\2|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/
		var reg_attrval  = /\\([0-9a-fA-F]{2,2})/g;
		var reg_sensitive       = /^(title|id|name|class|for|href|src)$/
		var reg_backslash = /\\/g;
		var reg_tag  = /^((?:[-\w\*]|[^\x00-\xa0]|\\.)+)/;//能使用getElementsByTagName处理的CSS表达式
		if ( trimLeft.test( "\xA0" ) ) {
			trimLeft = /^[\s\xA0]+/;
			trimRight = /[\s\xA0]+$/;
		}

		var hash_operator   = {
			"=": 1, 
			"!=": 2, 
			"|=": 3,
			"~=": 4, 
			"^=": 5, 
			"$=": 6, 
			"*=": 7
		};

		function sortOrder1( a, b ) {
			if ( a === b ) {
				sortOrder1.hasDuplicate = true;
				return 0;
			}
			if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
				return a.compareDocumentPosition ? -1 : 1;
			}
			return a.compareDocumentPosition(b) & 4 ? -1 : 1;
		};

		function sortOrder2( a, b ) {//处理旧式的标准浏览器与XML
			if ( a === b ) {
				sortOrder2.hasDuplicate = true;
				return 0;
			}
			var al, bl,
			ap = [],
			bp = [],
			aup = a.parentNode,
			bup = b.parentNode,
			cur = aup;
			//如果是属于同一个父节点，那么就比较它们在childNodes中的位置
			if ( aup === bup ) {
				return siblingCheck( a, b );
			// If no parents were found then the nodes are disconnected
			} else if ( !aup ) {
				return -1;

			} else if ( !bup ) {
				return 1;
			}
			// Otherwise they're somewhere else in the tree so we need
			// to build up a full list of the parentNodes for comparison
			while ( cur ) {
				ap.unshift( cur );
				cur = cur.parentNode;
			}

			cur = bup;

			while ( cur ) {
				bp.unshift( cur );
				cur = cur.parentNode;
			}

			al = ap.length;
			bl = bp.length;

			// Start walking down the tree looking for a discrepancy
			for ( var i = 0; i < al && i < bl; i++ ) {
				if ( ap[i] !== bp[i] ) {
					return siblingCheck( ap[i], bp[i] );
				}
			}
			// We ended someplace up the tree so do a sibling check
			return i === al ?
			siblingCheck( a, bp[i], -1 ) :
			siblingCheck( ap[i], b, 1 );
		};
		function siblingCheck( a, b, ret ) {
			if ( a === b ) {
				return ret;
			}
			var cur = a.nextSibling;

			while ( cur ) {
				if ( cur === b ) {
					return -1;
				}
				cur = cur.nextSibling;
			}
			return 1;
		};
		var slice = Array.prototype.slice,
		/**
		 * 将节点集合nodes处理成数组返回
		 * @param nodes:required,节点数组
		 * @param result:optional,数组，如果提供，处理nodes后的数组将附加在其元素后
		 * @param flag_multi:optional,为true表示去重，false不去重
		 */
		makeArray = function ( nodes, result, flag_multi ) {
			nodes = slice.call( nodes, 0 );
			if ( result ) {
				result.push.apply( result, nodes );
			}else{
				result = nodes;
			}
			return  flag_multi ? $.unique(result) : result;
		};
		//IE56789无法使用数组方法转换节点集合
		try {
			slice.call( $.html.childNodes, 0 )[0].nodeType;
		} catch( e ) {
			makeArray = function ( nodes, result ,flag_multi) {
				var ret = result || [], ri = ret.length;
				for(var i = 0,el ; el = nodes[i++];){
					ret[ri++] = el;
				}
				return flag_multi ? $.unique(ret) : ret;
			}
		}
		function _toHex(x, y) {
			return String.fromCharCode(parseInt(y, 16));
		}
		function parse_nth(expr) {
			var orig = expr;
			expr = expr.replace(/^\+|\s*/g, '');//清除无用的空白
			var match = (expr === "even" && "2n" || expr === "odd" && "2n+1" || !/\D/.test(expr) && "0n+" + expr || expr).match(/(-?)(\d*)n([-+]?\d*)/);
			return parse_nth[ orig ] = {
				a: (match[1] + (match[2] || 1)) - 0, 
				b: match[3] - 0
			};
		}
		function getElementsByTagName(tagName, els, flag_xml) {
			var method = "getElementsByTagName", elems = [], uniqResult = {}, prefix
			if(flag_xml && tagName.indexOf(":") > 0 && els.length && els[0].lookupNamespaceURI){
				var arr = tagName.split(":");
				prefix = arr[0];
				tagName = arr[1];
				method = "getElementsByTagNameNS";
				prefix = els[0].lookupNamespaceURI(prefix);
			}
			switch (els.length) {
				case 0:
					return elems;
				case 1:
					//在IE67下，如果存在一个name为length的input元素，下面的all.length返回此元素，而不是长度值
					var all =  prefix ? els[0][method](prefix,tagName) : els[0][method](tagName);
					for(var i = 0, ri = 0, el; el = all[i++];){
						if(el.nodeType === 1){//防止混入注释节点
							elems[ri++] = el
						}
					}
					return elems;
				default:
					for(i = 0, ri = 0; el = els[i++];){
						var nodes = prefix ? el[method](prefix,tagName) : el[method](tagName)
						for (var j = 0, node; node = nodes[j++];) {
							var uid = $.getUid(node);
							   
							if (!uniqResult[uid]) {
								uniqResult[uid] = elems[ri++] = node;
							}
						}
					}
					return elems;
			}
		}
		//IE9 以下的XML文档不能直接设置自定义属性
		var attrURL = $.oneObject('action,cite,codebase,data,href,longdesc,lowsrc,src,usemap', 2);
		var bools = $["@bools"] = "autofocus,autoplay,async,checked,controls,declare,disabled,defer,defaultChecked,"+
		"contentEditable,ismap,loop,multiple,noshade,open,noresize,readOnly,selected"
		var boolOne = $.oneObject(bools.toLowerCase() );
			
		//检测各种BUG（fixGetAttribute，fixHasAttribute，fixById，fixByTag）
		var fixGetAttribute,fixHasAttribute,fixById,fixByTag;
		var getHTMLText = new Function("els","return els[0]."+ ($.html.textContent ? "textContent" : "innerText") );

		new function(){
			var select = DOC.createElement("select");
			var option = select.appendChild( DOC.createElement("option") );
			option.setAttribute("selected","selected")
			option.className ="x"
			fixGetAttribute = option.getAttribute("class") != "x";
			select.appendChild( DOC.createComment("") );
			fixByTag = select.getElementsByTagName("*").length == 2
			var all = DOC.getElementsByTagName("*"), node, nodeType, comments = [], i = 0, j = 0;
			while ( (node = all[i++]) ) {  
				nodeType = node.nodeType;
				nodeType === 1 ? $.getUid(node) :
				nodeType === 8 ? comments.push(node) : 0;  
			}
			while ( (node = comments[j++]) ) {   
				node.parentNode.removeChild(node);
			}
			fixHasAttribute = select.hasAttribute ? !option.hasAttribute('selected') :true;
			
			var form = DOC.createElement("div"),
			id = "fixId" + (new Date()).getTime(),
			root = $.html;
			form.innerHTML = "<a name='" + id + "'/>";
			root.insertBefore( form, root.firstChild );
			fixById = !!DOC.getElementById( id ) ;
			root.removeChild(form )
		};

		//http://www.atmarkit.co.jp/fxml/tanpatsu/24bohem/01.html
		//http://msdn.microsoft.com/zh-CN/library/ms256086.aspx
		//https://developer.mozilla.org/cn/DOM/document.evaluate
		//http://d.hatena.ne.jp/javascripter/20080425/1209094795
		function getElementsByXPath(xpath,context,doc) {
			var result = [];
			try{
				if(global.DOMParser){//IE9支持DOMParser，但我们不能使用doc.evaluate!global.DOMParser
					var nodes = doc.evaluate(xpath, context, null, 7, null);
					for (var i = 0, n = nodes.snapshotLength; i < n; i++){
						result[i] =  nodes.snapshotItem(i)
					} 
				}else{
					nodes = context.selectNodes(xpath);
					for (i = 0, n = nodes.length; i < n; i++){
						result[i] =  nodes[i]
					} 
				}
			}catch(e){
				return false;
			}
			return result;
		};
		/**
			 * 选择器
			 * @param {String} expr CSS表达式
			 * @param {Node}   context 上下文（可选）
			 * @param {Array}  result  结果集(内部使用)
			 * @param {Array}  lastResult  上次的结果集(内部使用)
			 * @param {Boolean}flag_xml 是否为XML文档(内部使用)
			 * @param {Boolean}flag_multi 是否出现并联选择器(内部使用)
			 * @param {Boolean}flag_dirty 是否出现通配符选择器(内部使用)
			 * @return {Array} result
			 */
		//http://webbugtrack.blogspot.com/
		var Icarus = $.query = function(expr, contexts, result, lastResult, flag_xml,flag_multi,flag_dirty){
			result = result || [];
			contexts = contexts || DOC;
			var pushResult = makeArray;
			if(!contexts.nodeType){//实现对多上下文的支持
				contexts = pushResult(contexts);
				if(!contexts.length)
					return result
			}else{
				contexts = [contexts];
			}
			var rrelative = reg_combinator,//保存到本地作用域
			rquick = reg_quick,
			rBackslash = reg_backslash, rcomma = reg_comma,//用于切割并联选择器
			context = contexts[0],
			doc = context.ownerDocument || context,
			rtag = reg_tag,
			flag_all, uniqResult, elems, nodes, tagName, last, ri, uid;
			//将这次得到的结果集放到最终结果集中
			//如果要从多个上下文中过滤孩子
			expr = expr.replace(trimLeft, "").replace(trimRight, "");  
			flag_xml = flag_xml !== void 0 ? flag_xml : $.isXML(doc);
		   
			if (!flag_xml && doc.querySelectorAll2) {
				var query = expr;
				if(contexts.length > 2 || doc.documentMode == 8  && context.nodeType == 1  ){
					if(contexts.length > 2 )
						context = doc;
					query = ".fix_icarus_sqa "+query;//IE8也要使用类名确保查找范围
					for(var i = 0, node; node = contexts[i++];){
						if(node.nodeType === 1){
							node.className = "fix_icarus_sqa " + node.className;
						}
					}
				}
				if(doc.documentMode !== 8  || context.nodeName.toLowerCase() !== "object"){
					try{
						return pushResult( context.querySelectorAll(query), result, flag_multi);
					}catch(e){
					}finally{
						if(query.indexOf(".fix_icarus_sqa") === 0 ){//如果为上下文添加了类名，就要去掉类名
							for(i = 0; node = contexts[i++];){
								if(node.nodeType === 1){
									node.className =  node.className.replace("fix_icarus_sqa ","");
								}
							}
						}
					}
				}
			}
			var match = expr.match(rquick);
			if(match ){//对只有单个标签，类名或ID的选择器进行提速
				var value = match[2].replace(rBackslash,""), key = match[1];
				if (  key == "") {//tagName;
					nodes = getElementsByTagName(value,contexts,flag_xml);
				} else if ( key === "." && contexts.length === 1 ) {//className，并且上下文只有1个
					if(flag_xml){//如果XPATH查找失败，就会返回字符，那些我们就使用普通方式去查找
						nodes = getElementsByXPath("//*[@class='"+value+"']", context, doc);
					}else if(context.getElementsByClassName){
						nodes = context.getElementsByClassName( value );
					}
				}else if ( key === "#" && contexts.length === 1){//ID，并且上下文只有1个
					if( flag_xml){
						nodes = getElementsByXPath("//*[@id='"+value+"']", context, doc);
					//基于document的查找是不安全的，因为生成的节点可能还没有加入DOM树，比如$("<div id=\"A'B~C.D[E]\"><p>foo</p></div>").find("p")
					}else if(context.nodeType == 9){
						node = doc.getElementById(value);
						//IE67 opera混淆表单元素，object以及链接的ID与NAME
						//http://webbugtrack.blogspot.com/2007/08/bug-152-getelementbyid-returns.html
						nodes = !node ? [] : !fixById ? [node] : node.getAttributeNode("id").nodeValue === value ? [node] : false;
					}
				}
				if(nodes ){
					return pushResult( nodes, result, flag_multi );
				}
			}
			//执行效率应该是内大外小更高一写
			lastResult = contexts;
			if(lastResult.length){
				loop:
				while (expr && last !== expr) {
					flag_dirty = false;
					elems = null;
					uniqResult = {};
					//处理夹在中间的关系选择器（取得连接符及其后的标签选择器或通配符选择器）
					if (match = expr.match(rrelative)) {
						expr = RegExp.rightContext;
						elems = [];
						tagName = (flag_xml ? match[2] : match[2].toUpperCase()).replace(rBackslash,"") || "*";
						i = 0;
						ri = 0;
						flag_all = tagName === "*";// 表示无需判定tagName
						switch (match[1]) {//根据连接符取得种子集的亲戚，组成新的种子集
							case " "://后代选择器
								if(expr.length || match[2]){//如果后面还跟着东西或最后的字符是通配符
									elems = getElementsByTagName(tagName, lastResult, flag_xml);
								}else{
									elems = lastResult;
									break loop
								}
								break;
							case ">"://亲子选择器
								while((node = lastResult[i++])){
									for (node = node.firstChild; node; node = node.nextSibling){
										if (node.nodeType === 1 && (flag_all || tagName === node.nodeName)){
											elems[ri++] = node;
										}
									}
								}
								break;
							case "+"://相邻选择器
								while((node = lastResult[i++])){
									while((node = node.nextSibling)){
										if (node.nodeType === 1) {
											if (flag_all || tagName === node.nodeName)
												elems[ri++] = node;
											break;
										}
									}
								}
								break;
							case "~"://兄长选择器
								while((node = lastResult[i++])){
									while((node = node.nextSibling)){
										if (node.nodeType === 1 && (flag_all || tagName === node.nodeName)) {
											uid = $.getUid(node);
											if (uniqResult[uid]){
												break;
											}else {
												uniqResult[uid] = elems[ri++] = node;
											}
										}
									}
								}
								elems = $.unique(elems);
								break;
						}
					}else if(match = expr.match(rtag)){//处理位于最开始的或并联选择器之后的标签选择器或通配符
						expr = RegExp.rightContext;
						elems = getElementsByTagName(match[1].replace(rBackslash,""), lastResult, flag_xml);
					}
					   
					if(expr){
						var arr = Icarus.filter(expr, elems, lastResult, doc, flag_xml);
						expr = arr[0];
						elems = arr[1];
						if (!elems) {
							flag_dirty = true;
							elems = getElementsByTagName("*", lastResult, flag_xml);
						}
						if (match = expr.match(rcomma)) {
							expr = RegExp.rightContext;
							pushResult(elems, result);
							return Icarus(expr, contexts, result, [], flag_xml, true, flag_dirty);
						}else{
							lastResult = elems;
						}
					}
						
				}
			}
			if (flag_multi) {
				if (elems.length){
					return pushResult(elems, result,flag_multi);
				}
			}else if (DOC !== doc || fixByTag && flag_dirty) {
				for (result = [], ri = 0, i = 0; node = elems[i++]; )
					if (node.nodeType === 1)
						result[ri++] = node;
				return result
			}
			return elems;
		}
		var onePosition = $.oneObject("eq|gt|lt|first|last|even|odd".split("|"));

		$.mix(Icarus, {
			//getAttribute总会返回字符串
			//http://reference.sitepoint.com/javascript/Element/getAttribute
			getAttribute : !fixGetAttribute ?
			function(elem, name) {
				return elem.getAttribute(name) || '';
			} :
			function(elem, name, flag_xml) {
				if(flag_xml)
					return elem.getAttribute(name) || '';
				name = name.toLowerCase();
				//http://jsfox.cn/blog/javascript/get-right-href-attribute.html
				if(attrURL[name]){//得到href属性里原始链接，不自动转绝对地址、汉字和符号都不编码
					return  elem.getAttribute(name, 2) || ''
				}
				if(name === "style"){
					return elem.style.cssText.toLowerCase();
				}
				if(elem.tagName === "INPUT" && name == "type"){
					return elem.getAttribute("type") || elem.type;//IE67无法辩识HTML5添加添加的input类型，如input[type=search]，不能使用el.type与el.getAttributeNode去取。
				}
				//布尔属性，如果为true时则返回其属性名，否则返回空字符串，其他一律使用getAttributeNode
				var attr = boolOne[name] ? (elem.getAttribute(name) ? name : '') :
				(elem = elem.getAttributeNode(name)) && elem.value || '';
				return reg_sensitive.test(name)? attr :attr.toLowerCase();
			},
			hasAttribute : !fixHasAttribute ?
			function(elem, name, flag_xml) {
				return flag_xml ?  !!elem.getAttribute(name) :elem.hasAttribute(name);
			} :
			function(elem, name) {
				//http://help.dottoro.com/ljnqsrfe.php
				name = name.toLowerCase();
				//如果这个显式设置的属性是""，即使是outerHTML也寻不见其踪影
				elem = elem.getAttributeNode(name);
				return !!(elem && (elem.specified || elem.nodeValue));
			},
			filter : function(expr, elems, lastResult, doc, flag_xml, flag_get){
				var rsequence = reg_sequence,
				rattrib = reg_attrib ,
				rpseudo = reg_pseudo,
				rBackslash = reg_backslash,
				rattrval  = reg_attrval,
				pushResult = makeArray,
				toHex = _toHex,
				_hash_op  = hash_operator,
				parseNth = parse_nth,
				match ,key, tmp;
				while ( match = expr.match(rsequence)) {//主循环
					expr = RegExp.rightContext;     
					key = ( match[2]|| "").replace(rBackslash,"");
					if (!elems) {//取得用于过滤的元素
						if (lastResult.length === 1 && lastResult[0] === doc){
							switch (match[1]) {
								case "#":
									if (!flag_xml) {//FF chrome opera等XML文档中也存在getElementById，但不能用
										tmp = doc.getElementById(key);
										if (!tmp) {
											elems = [];
											continue;
										}
										//处理拥有name值为"id"的控件的form元素
										if (fixById ? tmp.id === key : tmp.getAttributeNode("id").nodeValue === key) {
											elems = [tmp];
											continue;
										}
									}
									break;
								case ":":
									switch (key) {
										case "root":
											elems = [doc.documentElement];
											continue;
										case "link":
											elems = pushResult(doc.links || []);
											continue;
									}
									break;
							}
						}
						elems = getElementsByTagName("*", lastResult, flag_xml);//取得过滤元
					}
					//取得用于过滤的函数，函数参数或数组
					var filter = 0, flag_not = false, args; 
					switch (match[1]) {
						case "#"://ID选择器
							filter = ["id", "=", key];
							break;
						case "."://类选择器
							filter = ["class", "~=", key];
							break;
						case ":"://伪类选择器
							tmp = Icarus.pseudoAdapter[key];
							if (match = expr.match(rpseudo)) {
								expr = RegExp.rightContext;
								if(!!~key.indexOf("nth")){
									args = parseNth[match[1]] || parseNth(match[1]);
								}else{
									args = match[3] || match[2] || match[1]
								}
							}
							if (tmp){
								filter = tmp;
							}else if (key === "not") {
								flag_not = true;
								if (args === "*"){//处理反选伪类中的通配符选择器
									elems = [];
								}else if(reg_tag.test(args)){//处理反选伪类中的标签选择器
									tmp = [];
									match = flag_xml ? args : args.toUpperCase();
									for (var i = 0, ri = 0, elem; elem = elems[i++];)
										if (match !== elem.nodeName)
											tmp[ri++] = elem;
									elems = tmp;
								}else{
									var obj =  Icarus.filter(args, elems, lastResult, doc, flag_xml, true) ;
									filter = obj.filter;
									args   = obj.args;
								}
							}
							else{
								throw 'An invalid or illegal string was specified : "'+ key+'"!'
							}
							break
						default:
							filter = [key.toLowerCase()];  
							if (match = expr.match(rattrib)) {
								expr = RegExp.rightContext;
								if (match[1]) {
									filter[1] = match[1];//op
									filter[2] = match[3] || match[4];//对值进行转义
									filter[2] = filter[2] ? filter[2].replace(rattrval, toHex).replace(rBackslash,"") : "";
								}
							}
							break;
					}
					if(flag_get){
						return {
							filter:filter,
							args:args
						}
					}
					//如果条件都俱备，就开始进行筛选 
					if (elems.length && filter) {
						tmp = [];
						i = 0;
						ri = 0;
						if (typeof filter === "function") {//如果是一些简单的伪类
							if(onePosition[key]){
								//如果args为void则将集合的最大索引值传进去，否则将exp转换为数字
								args =  args === void 0 ? elems.length - 1 : ~~args;
								for (; elem = elems[i];){
									if(filter(i++, args) ^ flag_not)
										tmp[ri++] = elem;
								}
							}else{
								while((elem = elems[i++])){
									if ((!!filter(elem, args)) ^ flag_not)
										tmp[ri++] = elem;
								}
							}
						}else if (typeof filter.exec === "function"){//如果是子元素过滤伪类
							tmp = filter.exec({
								not: flag_not, 
								xml: flag_xml
							}, elems, args, doc);
						} else {
							var name = filter[0], op = _hash_op[filter[1]], val = filter[2]||"", flag, attr;
							if (!flag_xml && name === "class" && op === 4) {//如果是类名
								val = " " + val + " ";
								while((elem = elems[i++])){
									var className = elem.className;
									if (!!(className && (" " + className + " ").indexOf(val) > -1) ^ flag_not){
										tmp[ri++] = elem;
									}
								}
							} else {
								if(!flag_xml && op && val && !reg_sensitive.test(name)){
									val = val.toLowerCase();
								}
								if (op === 4){
									val = " " + val + " ";
								}
								while((elem = elems[i++])){
									if(!op){
										flag = Icarus.hasAttribute(elem,name,flag_xml);//[title]
									}else if(val === "" && op > 3){
										flag = false
									}else{
										attr = Icarus.getAttribute(elem,name,flag_xml);
										switch (op) {
											case 1:// = 属性值全等于给出值
												flag = attr === val;
												break;
											case 2://!= 非标准，属性值不等于给出值
												flag = attr !== val;
												break;
											case 3://|= 属性值以“-”分割成两部分，给出值等于其中一部分，或全等于属性值
												flag = attr === val || attr.substr(0, val.length + 1) === val + "-";
												break;
											case 4://~= 属性值为多个单词，给出值为其中一个。
												flag = attr && (" " + attr + " ").indexOf(val) >= 0;
												break;
											case 5://^= 属性值以给出值开头
												flag = attr  && attr.indexOf(val) === 0 ;
												break;
											case 6://$= 属性值以给出值结尾
												flag = attr  && attr.substr(attr.length - val.length) === val;
												break;
											case 7://*= 属性值包含给出值
												flag = attr  && attr.indexOf(val) >= 0;
												break;
										}
									}
									if (flag ^ flag_not)
										tmp[ri++] = elem;
								}
							}
						}
						elems = tmp;
					}
				}
				return [expr, elems];
			}
		});

		//===================构建处理伪类的适配器=====================
		var filterPseudoHasExp = function(strchild,strsibling, type){
			return {
				exec:function(flags,lastResult,args){
					var result = [], flag_not = flags.not,child = strchild, sibling = strsibling,
					ofType = type, cache = {},lock = {},a = args.a, b = args.b, i = 0, ri = 0, el, found ,diff,count;
					if(!ofType && a === 1 && b === 0 ){
						return flag_not ? [] : lastResult;
					}
					var checkName = ofType ? "nodeName" : "nodeType";
					for (; el = lastResult[i++];) {
						var parent = el.parentNode;
						var pid =  $.getUid(parent);
						if (!lock[pid]){
							count = lock[pid] = 1;
							var checkValue = ofType ? el.nodeName : 1;
							for(var node = parent[child];node;node = node[sibling]){
								if(node[checkName] === checkValue){
									pid = $.getUid(node);
									cache[pid] = count++;
								}
							}
						}
						diff = cache[$.getUid(el)] - b;
						found =  a === 0 ? diff === 0 : (diff % a === 0 && diff / a >= 0 );
						(found ^ flag_not) && (result[ri++] = el);
					}
					return  result;
				}
			};
		};
		function filterPseudoNoExp(name, isLast, isOnly) {
			var A = "var result = [], flag_not = flags.not, node, el, tagName, i = 0, ri = 0, found = 0; for (; node = el = lastResult[i++];found = 0) {"
			var B = "{0} while (!found && (node=node.{1})) { (node.{2} === {3})  && ++found;  }";
			var C = " node = el;while (!found && (node = node.previousSibling)) {  node.{2} === {3} && ++found;  }";
			var D =  "!found ^ flag_not && (result[ri++] = el);  }   return result";

			var start = isLast ? "nextSibling" : "previousSibling";
			var fills = {
				type: [" tagName = el.nodeName;", start, "nodeName", "tagName"],
				child: ["", start, "nodeType", "1"]
			}
			[name];
			var body = A+B+(isOnly ? C: "")+D;
			var fn = new Function("flags","lastResult",body.replace(/{(\d)}/g, function ($, $1) {
				return fills[$1];
			}));
			return {
				exec:fn
			}
		}

		function filterProp(str_prop, flag) {
			return {
				exec: function (flags, elems) {
					var result = [], prop = str_prop, flag_not = flag ? flags.not : !flags.not;
					for (var i = 0,ri = 0, elem; elem = elems[i++];)
						if ( elem[prop] ^ flag_not)
							result[ri++] = elem;//&& ( !flag || elem.type !== "hidden" )
					return result;
				}
			};
		};
		Icarus.pseudoAdapter = {
			root: function (el) {//标准
				return el === (el.ownerDocument || el.document).documentElement;
			},
			target: {//标准
				exec: function (flags, elems,_,doc) {
					var result = [], flag_not = flags.not;
					var win = doc.defaultView || doc.parentWindow;
					var hash = win.location.hash.slice(1);       
					for (var i = 0,ri = 0, elem; elem = elems[i++];)
						if (((elem.id || elem.name) === hash) ^ flag_not)
							result[ri++] = elem;
					return result;
				}
			},
			"first-child"    : filterPseudoNoExp("child", false, false),
			"last-child"     : filterPseudoNoExp("child", true,  false),
			"only-child"     : filterPseudoNoExp("child", true,  true),
			"first-of-type"  : filterPseudoNoExp("type",  false, false),
			"last-of-type"   : filterPseudoNoExp("type",  true,  false),
			"only-of-type"   : filterPseudoNoExp("type",  true,  true),//name, isLast, isOnly
			"nth-child"       : filterPseudoHasExp("firstChild", "nextSibling",     false),//标准
			"nth-last-child"  : filterPseudoHasExp("lastChild",  "previousSibling", false),//标准
			"nth-of-type"     : filterPseudoHasExp("firstChild", "nextSibling",     true),//标准
			"nth-last-of-type": filterPseudoHasExp("lastChild",  "previousSibling", true),//标准
			empty: {//标准
				exec: function (flags, elems) {   
					var result = [], flag_not = flags.not, check
					for (var i = 0, ri = 0, elem; elem = elems[i++];) {
						if(elem.nodeType == 1){
							if (!elem.firstChild ^ flag_not)
								result[ri++] = elem;
						}
					}
					return result;
				}
			},
			link: {//标准
				exec: function (flags, elems) {
					var links = (elems[0].ownerDocument || elems[0].document).links;
					if (!links) return [];
					var result = [],
					checked = {},
					flag_not = flags.not;
					for (var i = 0, ri = 0,elem; elem = links[i++];)
						checked[$.getUid(elem) ] = 1;
					for (i = 0; elem = elems[i++]; )
						if (checked[$.getUid(elem)] ^ flag_not)
							result[ri++] = elem;
					return result;
				}
			},
			lang: {//标准 CSS2链接伪类
				exec: function (flags, elems, arg) {
					var result = [], reg = new RegExp("^" + arg, "i"), flag_not = flags.not;
					for (var i = 0, ri = 0, elem; elem = elems[i++]; ){
						var tmp = elem;
						while (tmp && !tmp.getAttribute("lang"))
							tmp = tmp.parentNode;
						tmp = !!(tmp && reg.test(tmp.getAttribute("lang")));
						if (tmp ^ flag_not)
							result[ri++] = elem;
					}
					return result;
				}
			},
			active: function(el){
				return el === el.ownerDocument.activeElement;
			},
			focus:function(el){
				return (el.type|| el.href) && el === el.ownerDocument.activeElement;
			},
			indeterminate : function(node){//标准
				return node.indeterminate === true && node.type === "checkbox"
			},
			//http://www.w3.org/TR/css3-selectors/#UIstates
			enabled:  filterProp("disabled", false),//标准
			disabled: filterProp("disabled", true),//标准
			checked:  filterProp("checked", true),//标准
			contains: {
				exec: function (flags, elems, arg) {
					var res = [], elem = elems[0], fn = flags.xml ? $.getText: getHTMLText,
					flag_not = flags.not;
					for (var i = 0, ri = 0, elem; elem = elems[i++]; ){
						if ((!!~  fn( [elem] ).indexOf(arg)) ^ flag_not)
							res[ri++] = elem;
					}
					return res;
				}
			},
			//自定义伪类
			selected : function(el){
				el.parentNode && el.parentNode.selectedIndex;//处理safari的bug
				return el.selected === true;
			},
			header : function(el){
				return /h\d/i.test( el.nodeName );
			},
			button : function(el){
				return "button" === el.type || el.nodeName === "BUTTON";
			},
			input: function(el){
				return /input|select|textarea|button/i.test(el.nodeName);
			},
			parent : function( el ) {
				return !!el.firstChild;
			},
			has : function(el, expr){//孩子中是否拥有匹配expr的节点
				return !!$.query(expr,[el]).length;
			},
			//与位置相关的过滤器
			first: function(index){
				return index === 0;
			},
			last: function(index, num){
				return index === num;
			},
			even: function(index){
				return index % 2 === 0;
			},
			odd: function(index){
				return index % 2 === 1;
			},
			lt: function(index, num){
				return index < num;
			},
			gt: function(index, num){
				return index > num;
			},
			eq: function(index, num){
				return index ===  num;
			},
			hidden : function( el ) {
				return el.type === "hidden" || (!el.offsetWidth && !el.offsetHeight) || (el.currentStyle && el.currentStyle.display === "none") ;
			}
		}
		Icarus.pseudoAdapter.visible = function(el){
			return  !Icarus.pseudoAdapter.hidden(el);
		}

		"text,radio,checkbox,file,password,submit,image,reset".replace($.rword, function(name){
			Icarus.pseudoAdapter[name] = function(el){
				return (el.getAttribute("type") || el.type) === name;//避开HTML5新增类型导致的BUG，不直接使用el.type === name;
			}
		});
		   
	});
})(window);